﻿using System;
using JetBrains.ProjectModel;
using JetBrains.ReSharper.CodeInsight.Services.CamelTyping;
using JetBrains.ReSharper.Psi;
using JetBrains.ReSharper.Psi.Util;
using JetBrains.ReSharper.UnitTestExplorer;
using Objectware.Silverlight.Testing.MetaData;
using IMethod = JetBrains.ReSharper.Psi.IMethod;

namespace Objectware.Silverlight.Testing.Runner.Resharper.Elements
{
	[Serializable]
	public class MethodTestElement : TestElement, ITestMethod
	{
		public MethodTestElement(IUnitTestProvider provider,
									ClassTestElement @class,
									IProjectModelElement project,
									string declaringTypeName,
									string methodName,
									int order)
			: base(provider, @class, project, declaringTypeName)
		{
			this.Class = @class;
			this.MethodName = methodName;
			this.Order = order;
		}

		public ClassTestElement Class { get; private set;  }
		public string MethodName { get; private set; }
		public int Order { get; private set; }


		public override int GetHashCode()
		{
			int result = base.GetHashCode();
			result = (0x1d * result) + this.Class.GetHashCode();
			return ((0x1d * result) + this.MethodName.GetHashCode());
		}

		public override IDeclaredElement GetDeclaredElement()
		{
			ITypeElement declaredType = GetDeclaredType();

			if (declaredType != null)
			{
				foreach (ITypeMember member in MiscUtil.EnumerateMembers(declaredType, this.MethodName, true))
				{
					IMethod method = member as IMethod;

					if (method != null && !method.IsAbstract && method.TypeParameters.Length <= 0 &&
						method.AccessibilityDomain.DomainType == AccessibilityDomain.AccessibilityDomainType.PUBLIC)
					{
						return member;
					}
				}
			}

			return null;
		}

		public override string GetKind()
		{
			return "Silverlight Test";
		}

		public override bool Matches(string filter, PrefixMatcher matcher)
		{
			foreach (UnitTestElementCategory category in GetCategories())
			{
				if (matcher.IsMatch(category.Name))
				{
					return true;
				}
			}

			if (!this.Class.Matches(filter, matcher))
			{
				return matcher.IsMatch(this.MethodName);
			}

			return true;
		}

		public override bool IsNameIdentical(TestElement element)
		{
			return this.GetTypeClrName() == element.GetTypeClrName();
		}


		#region IMethod Members

		public Objectware.Silverlight.Testing.MetaData.IClass Type
		{
			get { return this.Class; }
		}

		public string Name
		{
			get { return this.MethodName; }
		}

		public bool IsPublic
		{
			get { return true; }
		}

		public bool IsStatic
		{
			get { return false; }
		}

		#endregion
	}
}
